package main

import (
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"prometheus/utils"
	"strconv"
	"strings"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/log"
)

// 设计上，resourcemanger需要手动探测活跃节点

var (
	listenAddress    = flag.String("web.listen-address", ":9075", "暴露指标的监听地址，默认9075.") //设置成ip:port的格式，似乎更容易进行更改
	metricsPath      = flag.String("web.telemetry-path", "/metrics", "暴露指标的路由.")
	clientConfFile   = flag.String("yarn-site-path", "/etc/hadoop/conf/yarn-site.xml", "")
	resourceConfFile = flag.String("schedule-conf-path", "./schedule-conf.xml", "集群的资源队列配置，支持动态刷新")
	timeout          = flag.String("get.timeout-seconds", "5", "请求超时的时间")
)

type XMLConf struct {
	XMLName     xml.Name      `xml:"queue"`
	ResourceXML []ResourceXML `xml:"resource"`
}

type ResourceXML struct {
	Serial string `xml:"serial"`
	Name   string `xml:"name"`
	User   string `xml:"user"`
}

func (x *XMLConf) ReadXML(path string) error {
	xmlFile, err := os.Open(path)
	if err != nil {
		log.Error("Error opening file: %s", path)
		return err
	}
	defer xmlFile.Close()
	data, err := ioutil.ReadAll(xmlFile)
	if err != nil {
		log.Error("Error reading file: %s", path)
		return err
	}
	err = xml.Unmarshal(data, &x)
	if err != nil {
		log.Error("Error unmarshal xml.")
		return err
	}
	return nil
}

func (x *XMLConf) GetQueue() (quelist []string) {
	for _, v := range x.ResourceXML {
		t := fmt.Sprintf("Hadoop:service=ResourceManager,name=QueueMetrics,q%s=%s,user=%s", v.Serial, v.Name, v.User)
		quelist = append(quelist, t)
	}
	return quelist
}

type Exporter struct {
	url string
	c   utils.ResourceManagerConf
	// 总览信息"Hadoop:service=ResourceManager,name=ClusterMetrics"
	NumActiveNMs           prometheus.Gauge // 活动NM
	NumLostNMs             prometheus.Gauge // 失联NM
	NumDecommissioningNMs  prometheus.Gauge // 下线中的NM
	NumDecommissionedNMs   prometheus.Gauge // 已下线的NM
	NumUnhealthyNMs        prometheus.Gauge // 不健康的NM
	NumRebootedNMs         prometheus.Gauge // 重启的NM
	NumShutdownNMs         prometheus.Gauge // 已停止的NM
	AMLaunchDelayNumOps    prometheus.Gauge // AM启动数量
	AMLaunchDelayAvgTime   prometheus.Gauge // AM启动延迟
	AMRegisterDelayNumOps  prometheus.Gauge // AM注册数量
	AMRegisterDelayAvgTime prometheus.Gauge // AM注册延迟
	// 资源总览 Hadoop:service=ResourceManager,name=QueueMetrics,q0=root,q1=default
	// 总量算法：allocated+availabled+reserved
	AllocatedVCores *prometheus.Desc // 已分配的vcore
	ReservedVCores  *prometheus.Desc // 驻留vcore
	AvailableVCores *prometheus.Desc // 空闲vcore
	PendingVCores   *prometheus.Desc // 等待分配的vcore
	AllocatedMB     *prometheus.Desc // 已分配的内存
	AvailableMB     *prometheus.Desc // 可用内存
	PendingMB       *prometheus.Desc // 等待分配的内存
	ReservedMB      *prometheus.Desc // 驻留内存
	// 任务运行指标
	AppsSubmitted *prometheus.Desc // 提交任务总数
	AppsRunning   *prometheus.Desc // 在运行的任务数
	AppsPending   *prometheus.Desc // 等待资源的任务数
	AppsCompleted *prometheus.Desc // 完成的任务数量
	AppsKilled    *prometheus.Desc // 被kill的任务数量
	AppsFailed    *prometheus.Desc // 失败任务数量
	running_0     *prometheus.Desc // 运行时间0<t<60分钟的任务
	running_60    *prometheus.Desc // 运行时间60<t<300分钟的任务
	running_300   *prometheus.Desc // 运行时间300<t<1440分钟的任务
	running_1440  *prometheus.Desc // 运行时间1440<t<∞的任务

	//RPC指标
	RpcQueueTimeNumOps       prometheus.Gauge //Rpc被调用次数 "name": "Hadoop:service=ResourceManager,name=RpcActivityForPort8030",
	RpcQueueTimeAvgTime      prometheus.Gauge //Rpc队列平均耗时
	RpcProcessingTimeNumOps  prometheus.Gauge //Rpc被调用次数，和RpcQueueTimeNumOps一样
	RpcProcessingTimeAvgTime prometheus.Gauge //Rpc平均处理耗
	//GC指标
	heapMemoryUsageCommitted prometheus.Gauge
	heapMemoryUsageInit      prometheus.Gauge //JVM内存给定值，单位为bytes
	heapMemoryUsageMax       prometheus.Gauge
	heapMemoryUsageUsed      prometheus.Gauge //JVM内存使用值，单位为bytes
	// 日志指标
	LogFatal prometheus.Gauge
	LogError prometheus.Gauge
	LogWarn  prometheus.Gauge
	LogInfo  prometheus.Gauge
	// 运行指标
	StartTime               prometheus.Gauge
	Uptime                  prometheus.Gauge //运行时长
	SystemLoadAverage       prometheus.Gauge // 操作系统平均负载 "name": "java.lang:type=OperatingSystem"
	MaxFileDescriptorCount  prometheus.Gauge
	OpenFileDescriptorCount prometheus.Gauge // 打开的文件描述符
	TotalPhysicalMemorySize prometheus.Gauge // 服务器物理内存
	FreePhysicalMemorySize  prometheus.Gauge // 空闲物理内存
	AvailableProcessors     prometheus.Gauge
	ServerActive            prometheus.Gauge // 服务状态
	//其他健康指标
	isActive prometheus.Gauge //是否是Active的
}

// 指标格式定义：metrics_name{job="XX",ip="10.30.108.2",nameservice=""}

//创建指标
func NewExporter(url string, c *utils.ResourceManagerConf) *Exporter {
	return &Exporter{
		url: url,
		c:   *c,
		NumActiveNMs: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_NumActiveNms",
			Help:        "NumActiveNms",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		NumLostNMs: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_NumLostNMs",
			Help:        "NumLostNMs",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		NumDecommissioningNMs: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_NumDecommissioningNMs",
			Help:        "NumDecommissioningNMs",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		NumDecommissionedNMs: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_NumDecommissionedNMs",
			Help:        "NumDecommissionedNMs",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		NumUnhealthyNMs: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_NumUnhealthyNMs",
			Help:        "NumUnhealthyNMs",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		NumRebootedNMs: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_NumRebootedNMs",
			Help:        "NumRebootedNMs",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		NumShutdownNMs: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_NumShutdownNMs",
			Help:        "NumShutdownNMs",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		AMLaunchDelayNumOps: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_AMLaunchDelayNumOps",
			Help:        "AMLaunchDelayNumOps",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		AMLaunchDelayAvgTime: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_AMLaunchDelayAvgTime",
			Help:        "AMLaunchDelayAvgTime",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		AMRegisterDelayNumOps: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_AMRegisterDelayNumOps",
			Help:        "AMRegisterDelayNumOps",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		AMRegisterDelayAvgTime: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_AMRegisterDelayAvgTime",
			Help:        "AMRegisterDelayAvgTime",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		AllocatedVCores: prometheus.NewDesc(
			"ResourceManager_AllocatedVCores",
			"AllocatedVCores",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		ReservedVCores: prometheus.NewDesc(
			"ResourceManager_ReservedVCores",
			"ReservedVCores",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AvailableVCores: prometheus.NewDesc(
			"ResourceManager_AvailableVCores",
			"AvailableVCores",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		PendingVCores: prometheus.NewDesc(
			"ResourceManager_PendingVCores",
			"PendingVCores",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AllocatedMB: prometheus.NewDesc(
			"ResourceManager_AllocatedMB",
			"AllocatedMB",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AvailableMB: prometheus.NewDesc(
			"ResourceManager_AvailableMB",
			"AvailableMB",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		PendingMB: prometheus.NewDesc(
			"ResourceManager_PendingMB",
			"PendingMB",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		ReservedMB: prometheus.NewDesc(
			"ResourceManager_ReservedMB",
			"ReservedMB",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AppsSubmitted: prometheus.NewDesc(
			"ResourceManager_AppsSubmitted",
			"AppsSubmitted",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AppsRunning: prometheus.NewDesc(
			"ResourceManager_AppsRunning",
			"AppsRunning",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AppsPending: prometheus.NewDesc(
			"ResourceManager_AppsPending",
			"AppsPending",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AppsCompleted: prometheus.NewDesc(
			"ResourceManager_AppsCompleted",
			"AppsCompleted",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AppsKilled: prometheus.NewDesc(
			"ResourceManager_AppsKilled",
			"AppsKilled",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		AppsFailed: prometheus.NewDesc(
			"ResourceManager_AppsFailed",
			"AppsFailed",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		running_0: prometheus.NewDesc(
			"ResourceManager_running_0",
			"running time < 60min",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		running_60: prometheus.NewDesc(
			"ResourceManager_running_60",
			"60min < running time < 300min",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		running_300: prometheus.NewDesc(
			"ResourceManager_running_300",
			"300min < running time < 1440min",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		running_1440: prometheus.NewDesc(
			"ResourceManager_running_1440",
			"running time > 1440min",
			[]string{"serverip", "resourcemangerid", "queue", "user"},
			prometheus.Labels{},
		),
		RpcQueueTimeNumOps: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_RpcQueueTimeNumOps",
			Help:        "RpcQueueTimeNumOps",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		RpcQueueTimeAvgTime: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_RpcQueueTimeAvgTime",
			Help:        "RpcQueueTimeAvgTime",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		RpcProcessingTimeNumOps: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_RpcProcessingTimeNumOps",
			Help:        "RpcProcessingTimeNumOps",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		RpcProcessingTimeAvgTime: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_RpcProcessingTimeAvgTime",
			Help:        "RpcProcessingTimeAvgTime",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		heapMemoryUsageCommitted: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_heapMemoryUsageCommitted",
			Help:        "heapMemoryUsageCommitted",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		heapMemoryUsageInit: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_heapMemoryUsageInit",
			Help:        "heapMemoryUsageInit",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		heapMemoryUsageMax: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_heapMemoryUsageMax",
			Help:        "heapMemoryUsageMax",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		heapMemoryUsageUsed: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_heapMemoryUsageUsed",
			Help:        "heapMemoryUsageUsed",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		LogFatal: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_LogFatal",
			Help:        "LogFatal",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		LogError: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_LogError",
			Help:        "LogError",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		LogInfo: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_LogInfo",
			Help:        "LogInfo",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		LogWarn: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_LogWarn",
			Help:        "LogWarn",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		StartTime: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_StartTime",
			Help:        "StartTime",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		Uptime: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_Uptime",
			Help:        "Uptime",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		SystemLoadAverage: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_SystemLoadAverage",
			Help:        "SystemLoadAverage",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		OpenFileDescriptorCount: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_OpenFileDescriptorCount",
			Help:        "OpenFileDescriptorCount",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		MaxFileDescriptorCount: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_MaxFileDescriptorCount",
			Help:        "MaxFileDescriptorCount",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		TotalPhysicalMemorySize: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_TotalPhysicalMemorySize",
			Help:        "TotalPhysicalMemorySize",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		FreePhysicalMemorySize: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_FreePhysicalMemorySize",
			Help:        "FreePhysicalMemorySize",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		AvailableProcessors: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_AvailableProcessors",
			Help:        "AvailableProcessors",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		ServerActive: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_ServerActive",
			Help:        "ServerActive",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
		isActive: prometheus.NewGauge(prometheus.GaugeOpts{
			Name:        "ResourceManager_isActive",
			Help:        "isActive",
			ConstLabels: map[string]string{"serverip": c.ServerIP, "resourcemangerid": c.ResourceMangerID},
		}),
	}
}

// 定义指标的描述
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.heapMemoryUsageCommitted.Describe(ch)
	e.heapMemoryUsageInit.Describe(ch)
	e.heapMemoryUsageMax.Describe(ch)
	e.heapMemoryUsageUsed.Describe(ch)
	e.isActive.Describe(ch)
}

//采集器方法
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
	// 超时处理
	t, err := strconv.Atoi(*timeout)
	client := http.Client{
		Timeout: time.Duration(t * int(time.Second)),
	}
	e.ServerActive.Set(0)
	resp, err := client.Get(e.url)
	if err != nil {
		e.ServerActive.Collect(ch)
		log.Error(err)
		return
	}
	if resp.StatusCode != 200 {
		e.ServerActive.Set(1)
		e.ServerActive.Collect(ch)
		if resp.StatusCode == 307 {
			e.isActive.Set(0)
			e.isActive.Collect(ch)
		}
		return
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Error(err)
	}
	var f interface{}
	err = json.Unmarshal(data, &f)
	if err != nil {
		log.Error(err)
	}
	m := f.(map[string]interface{})
	var nameList = m["beans"].([]interface{})
	e.ServerActive.Set(1) // 如果获取到数据了，就是活动服务
	e.isActive.Set(1)
	// 读取队列资源配置，进行适配
	sc := XMLConf{}
	if err := sc.ReadXML(*resourceConfFile); err != nil {
		log.Error(err)
		panic(1)
	}
	for _, nameData := range nameList {
		nameDataMap := nameData.(map[string]interface{})
		if nameDataMap["name"] == "Hadoop:service=ResourceManager,name=ClusterMetrics" {
			t, _ := net.ResolveIPAddr("ip", nameDataMap["tag.Hostname"].(string))
			if t.IP.String() != e.c.ServerIP {
				e.isActive.Set(0)
			}
			e.NumActiveNMs.Set(nameDataMap["NumActiveNMs"].(float64))
			e.NumLostNMs.Set(nameDataMap["NumLostNMs"].(float64))
			defer func() {
				if err := nameDataMap["NumDecommissioningNMs"]; err != nil {
					e.NumDecommissioningNMs.Set(0)
				}
			}()
			e.NumDecommissionedNMs.Set(nameDataMap["NumDecommissionedNMs"].(float64))
			e.NumUnhealthyNMs.Set(nameDataMap["NumUnhealthyNMs"].(float64))
			e.NumRebootedNMs.Set(nameDataMap["NumRebootedNMs"].(float64))
			e.NumShutdownNMs.Set(nameDataMap["NumShutdownNMs"].(float64))
			e.AMLaunchDelayNumOps.Set(nameDataMap["AMLaunchDelayNumOps"].(float64))
			e.AMLaunchDelayAvgTime.Set(nameDataMap["AMLaunchDelayAvgTime"].(float64))
			e.AMRegisterDelayNumOps.Set(nameDataMap["AMRegisterDelayNumOps"].(float64))
			e.AMRegisterDelayAvgTime.Set(nameDataMap["AMRegisterDelayAvgTime"].(float64))
		} else if nameDataMap["name"] == "Hadoop:service=ResourceManager,name=RpcActivityForPort"+e.c.RpcPort {
			e.RpcQueueTimeNumOps.Set(nameDataMap["RpcQueueTimeNumOps"].(float64))
			e.RpcQueueTimeAvgTime.Set(nameDataMap["RpcQueueTimeAvgTime"].(float64))
			e.RpcProcessingTimeNumOps.Set(nameDataMap["RpcProcessingTimeNumOps"].(float64))
			e.RpcProcessingTimeAvgTime.Set(nameDataMap["RpcProcessingTimeAvgTime"].(float64))
		} else if nameDataMap["name"] == "java.lang:type=Memory" {
			heapMemoryUsage := nameDataMap["HeapMemoryUsage"].(map[string]interface{})
			e.heapMemoryUsageCommitted.Set(heapMemoryUsage["committed"].(float64))
			e.heapMemoryUsageInit.Set(heapMemoryUsage["init"].(float64))
			e.heapMemoryUsageMax.Set(heapMemoryUsage["max"].(float64))
			e.heapMemoryUsageUsed.Set(heapMemoryUsage["used"].(float64))
		} else if nameDataMap["name"] == "Hadoop:service=ResourceManager,name=JvmMetrics" {
			e.LogError.Set(nameDataMap["LogError"].(float64))
			e.LogFatal.Set(nameDataMap["LogFatal"].(float64))
			e.LogInfo.Set(nameDataMap["LogInfo"].(float64))
			e.LogWarn.Set(nameDataMap["LogWarn"].(float64))
		} else if nameDataMap["name"] == "java.lang:type=Runtime" {
			e.StartTime.Set(nameDataMap["StartTime"].(float64))
			e.Uptime.Set(nameDataMap["Uptime"].(float64))
		} else if nameDataMap["name"] == "java.lang:type=OperatingSystem" {
			e.SystemLoadAverage.Set(nameDataMap["SystemLoadAverage"].(float64))
			e.OpenFileDescriptorCount.Set(nameDataMap["OpenFileDescriptorCount"].(float64))
			e.TotalPhysicalMemorySize.Set(nameDataMap["TotalPhysicalMemorySize"].(float64))
			e.FreePhysicalMemorySize.Set(nameDataMap["FreePhysicalMemorySize"].(float64))
			e.MaxFileDescriptorCount.Set(nameDataMap["MaxFileDescriptorCount"].(float64))
			e.AvailableProcessors.Set(nameDataMap["AvailableProcessors"].(float64))
		} else if strings.Contains(nameDataMap["name"].(string), "name=QueueMetrics") {
			for _, v := range sc.ResourceXML {
				que := fmt.Sprintf("Hadoop:service=ResourceManager,name=QueueMetrics,q%s=%s,user=%s", v.Serial, v.Name, v.User)
				if nameDataMap["name"] == que {
					ch <- prometheus.MustNewConstMetric(
						e.AllocatedVCores,
						prometheus.GaugeValue,
						nameDataMap["AllocatedVCores"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.ReservedVCores,
						prometheus.GaugeValue,
						nameDataMap["ReservedVCores"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AvailableVCores,
						prometheus.GaugeValue,
						nameDataMap["AvailableVCores"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.PendingVCores,
						prometheus.GaugeValue,
						nameDataMap["PendingVCores"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AllocatedMB,
						prometheus.GaugeValue,
						nameDataMap["AllocatedMB"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AvailableMB,
						prometheus.GaugeValue,
						nameDataMap["AvailableMB"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.PendingMB,
						prometheus.GaugeValue,
						nameDataMap["PendingMB"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.ReservedMB,
						prometheus.GaugeValue,
						nameDataMap["ReservedMB"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AppsSubmitted,
						prometheus.GaugeValue,
						nameDataMap["AppsSubmitted"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AppsRunning,
						prometheus.GaugeValue,
						nameDataMap["AppsRunning"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AppsPending,
						prometheus.GaugeValue,
						nameDataMap["AppsPending"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AppsCompleted,
						prometheus.GaugeValue,
						nameDataMap["AppsCompleted"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AppsKilled,
						prometheus.GaugeValue,
						nameDataMap["AppsKilled"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.AppsFailed,
						prometheus.GaugeValue,
						nameDataMap["AppsFailed"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.running_0,
						prometheus.GaugeValue,
						nameDataMap["running_0"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.running_60,
						prometheus.GaugeValue,
						nameDataMap["running_60"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.running_300,
						prometheus.GaugeValue,
						nameDataMap["running_300"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
					ch <- prometheus.MustNewConstMetric(
						e.running_1440,
						prometheus.GaugeValue,
						nameDataMap["running_1440"].(float64),
						e.c.ServerIP, e.c.ResourceMangerID, v.Name, v.User,
					)
				}
			}
		}
		// 资源队列监控
	}
	e.NumActiveNMs.Collect(ch)
	e.NumLostNMs.Collect(ch)
	e.NumDecommissionedNMs.Collect(ch)
	e.NumDecommissioningNMs.Collect(ch)
	e.NumUnhealthyNMs.Collect(ch)
	e.NumRebootedNMs.Collect(ch)
	e.NumShutdownNMs.Collect(ch)
	e.AMLaunchDelayNumOps.Collect(ch)
	e.AMLaunchDelayAvgTime.Collect(ch)
	e.AMRegisterDelayNumOps.Collect(ch)
	e.AMRegisterDelayAvgTime.Collect(ch)
	e.RpcQueueTimeNumOps.Collect(ch)
	e.RpcQueueTimeAvgTime.Collect(ch)
	e.RpcProcessingTimeNumOps.Collect(ch)
	e.RpcProcessingTimeAvgTime.Collect(ch)
	e.heapMemoryUsageCommitted.Collect(ch)
	e.heapMemoryUsageInit.Collect(ch)
	e.heapMemoryUsageMax.Collect(ch)
	e.heapMemoryUsageUsed.Collect(ch)
	e.LogFatal.Collect(ch)
	e.LogError.Collect(ch)
	e.LogInfo.Collect(ch)
	e.LogWarn.Collect(ch)
	e.StartTime.Collect(ch)
	e.Uptime.Collect(ch)
	e.SystemLoadAverage.Collect(ch)
	e.MaxFileDescriptorCount.Collect(ch)
	e.OpenFileDescriptorCount.Collect(ch)
	e.TotalPhysicalMemorySize.Collect(ch)
	e.FreePhysicalMemorySize.Collect(ch)
	e.AvailableProcessors.Collect(ch)
	e.ServerActive.Collect(ch)
	e.isActive.Collect(ch)
}

func main() {
	flag.Parse()
	log.Info("Hadoop Exporter make By Lijiadong(Meepod) (๑•̀ㅂ•́)و✧")
	var x utils.XMLConf
	err := x.ReadXML(*clientConfFile)
	if err != nil {
		log.Errorln(err)
	}
	conf := x.CreateResourceManagerConf()
	resourcemanagerJmxUrl := ""
	if conf.HttpsOpen {
		resourcemanagerJmxUrl = "https://" + conf.ServerIP + ":" + conf.HttpsPort + "/jmx"
	} else {
		resourcemanagerJmxUrl = "http://" + conf.ServerIP + ":" + conf.HttpPort + "/jmx"
	}
	exporter := NewExporter(resourcemanagerJmxUrl, &conf)
	prometheus.MustRegister(exporter)
	log.Printf("Starting Server: %s", *listenAddress)
	http.Handle(*metricsPath, prometheus.Handler())
	http.HandleFunc("/status", func(rw http.ResponseWriter, r *http.Request) {
		rw.Write([]byte("Hadoop Exporter Healthy."))
	})
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`<html>
		<head><title>Resourcemanager Exporter</title></head>
		<body>
		<h1>Resourcemanager Exporter By Meepo</h1>
		<h2>The greatest test of courage on earth is to bear defeat without losing heart</h2>
		<p><a href="` + *metricsPath + `">Metrics</a></p>
		</body>
		</html>`))
	})
	http.HandleFunc("/quit", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hadoop Exporter will exit."))
		os.Exit(0)
	})
	err = http.ListenAndServe(*listenAddress, nil)
	if err != nil {
		log.Fatal(err)
	}
}
